#include "pch.hpp"
#include "ProjectItem.hpp"
#include "Project.hpp"

using namespace Engine;
using namespace Engine::Edit;




ProjectItem::ProjectItem(QString name)
	: m_name(name)
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

ProjectItem::ProjectItem(weak_ptr parent, QString name)
	: m_parent(parent)
	, m_name(name)
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

void ProjectItem::post_create(ptr _this)
{
	m_this = _this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




ProjectItem::Type ProjectItem::type() const
{
	return FolderType;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

QString ProjectItem::name() const
{
	return m_name;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void ProjectItem::setName(QString name)
{
	m_name = name;
	root()->emitModified(m_this, weak_ptr(), NameChanged);
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void ProjectItem::add(ProjectItem::ptr item)
{
	auto parent = item->parent();
	if(parent && parent != shared_from_this())
		parent->remove(item);
	item->m_parent = weak_from_this();


	// We will not add anything if a slot disagrees with adding an item
	auto r = root();
	auto disagrees = r->emitModified(m_this, item, CanAddChild);
	if(disagrees)
		return;

	r->emitModified(m_this, item, BeginAddChild);

	m_children.push_back(item);

	r->emitModified(m_this, item, EndAddChild);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

void ProjectItem::remove(ProjectItem::ptr item)
{
	verify(item->parent() == shared_from_this());

	for(auto i = m_children.begin(); i != m_children.end(); ++i)
	{
		if(*i == item)
		{
			auto r = root();

			// We will not remove anything if a slot disagrees with this
			auto disagrees = r->emitModified(m_this, item, CanRemoveChild);
			if(disagrees == Disagree)
				return;

			r->emitModified(m_this, item, BeginRemoveChild);

			item->m_parent.reset();
			m_children.erase(i);

			r->emitModified(m_this, item, EndRemoveChild);

			return;
		}
	}
}
///////////////////////////////////////////////////////////////////////////////////////////////////




QString ProjectItem::freeName(QString pattern) const
{
	verify(pattern.contains("%1"));

	QString name;
	int n = 0;
	do
	{
		if(n > 0)
			name = pattern.arg(n);
		else
			name = pattern.arg("");

		++n;
	} while(child(name));

	return name;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




const ProjectItem::Items& ProjectItem::children() const
{
	return m_children;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

std::size_t ProjectItem::numChildren() const
{
	return m_children.size();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

ProjectItem::ptr ProjectItem::child(QString name) const
{
	for(auto i = m_children.begin(); i != m_children.end(); ++i)
	{
		if((*i)->name() == name)
			return *i;
	}

	return ptr();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

ProjectItem::ptr ProjectItem::child(std::size_t num) const
{
	if(num >= m_children.size())
		return ptr();
	else
		return m_children[num];
}
///////////////////////////////////////////////////////////////////////////////////////////////////

std::size_t ProjectItem::index(ptr child) const
{
	std::size_t index = 0;
	for(auto i = m_children.begin(); i != m_children.end(); ++i, ++index)
	{
		if(*i == child)
			return index;
	}

	throw invalid_value_exception(child);
}
///////////////////////////////////////////////////////////////////////////////////////////////////

bool ProjectItem::isParentOf(ProjectItem::ptr item) const
{
	if(!item)
		return false;

	auto _this = m_this.lock();

	do
	{
		item = item->parent();
		if(item == _this)
			return true;
	} while(item != nullptr);

	return false;
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void ProjectItem::load(AbstractDomInputStream& stream)
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

void ProjectItem::save(AbstractDomOutputStream& stream) const
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

ProjectItem::weak_ptr ProjectItem::weak_from_this()
{
	return m_this;
}
///////////////////////////////////////////////////////////////////////////////////////////////////

ProjectItem::ptr ProjectItem::shared_from_this()
{
	return m_this.lock();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

ProjectItem::ptr ProjectItem::parent()
{
	return m_parent.lock();
}
///////////////////////////////////////////////////////////////////////////////////////////////////

Project::ptr ProjectItem::root()
{
	auto _this  = m_this.lock();
	ptr p;

	do
	{
		p = _this->parent();
		if(p)
			_this = p;
	} while(p != nullptr);

	return boost::shared_dynamic_cast<Project>(_this);
}
///////////////////////////////////////////////////////////////////////////////////////////////////
